const fs = require('fs').promises;
const path = require('path');
const { existsSync, lstatSync } = require('fs');

// 从命令行参数获取项目根目录，默认使用当前目录
let projectRoot = process.cwd();

// 检查命令行参数
if (process.argv.length > 2) {
  const providedPath = process.argv[2];
  const resolvedPath = path.resolve(providedPath);
  if (existsSync(resolvedPath) && lstatSync(resolvedPath).isDirectory()) {
    projectRoot = resolvedPath;
  } else {
    console.error(`错误: 路径 "${providedPath}" 不存在或非目录`);
    process.exit(1);
  }
}

// 配置项
const config = {
  projectRoot,
  imageExtensions: ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp'],
  codeExtensions: ['.js', '.jsx', '.ts', '.tsx', '.html', '.css', '.scss', '.vue', '.json', '.ux', '.less'],
  ignoreDirs: ['node_modules', '.git', 'dist', 'build', 'out', '.vscode', '.idea'],
  ignoreFiles: ['.DS_Store']
};

/**
 * 检查路径是否应被忽略
 */
function shouldIgnore(filePath) {
  const relativePath = path.relative(config.projectRoot, filePath);
  // 忽略指定目录
  for (const dir of config.ignoreDirs) {
    if (relativePath.startsWith(dir + path.sep) || relativePath === dir) return true;
  }
  // 忽略指定文件
  const fileName = path.basename(filePath);
  if (config.ignoreFiles.includes(fileName)) return true;
  return false;
}

/**
 * 递归收集图片文件（含体积信息）
 */
async function collectImageFiles(dir) {
  let results = [];
  try {
    const entries = await fs.readdir(dir, { withFileTypes: true });
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      if (shouldIgnore(fullPath)) continue;
      if (entry.isDirectory()) {
        const subImages = await collectImageFiles(fullPath);
        results = [...results, ...subImages];
      } else if (entry.isFile()) {
        const ext = path.extname(entry.name).toLowerCase();
        if (config.imageExtensions.includes(ext)) {
          try {
            // 获取文件体积（字节 & KB 格式化）
            const stat = await fs.stat(fullPath);
            const size = stat.size;
            const sizeKB = (size / 1024).toFixed(2);
            results.push({
              path: fullPath,
              name: entry.name,
              dir,
              size,
              sizeKB
            });
          } catch (err) {
            console.error(`获取 ${fullPath} 体积失败:`, err.message);
            results.push({
              path: fullPath,
              name: entry.name,
              dir,
              size: 0,
              sizeKB: '获取失败'
            });
          }
        }
      }
    }
  } catch (err) {
    console.error(`读取目录 ${dir} 失败:`, err.message);
  }
  return results;
}

/**
 * 递归收集代码文件
 */
async function collectCodeFiles(dir) {
  let results = [];
  try {
    const entries = await fs.readdir(dir, { withFileTypes: true });
    for (const entry of entries) {
      const fullPath = path.join(dir, entry.name);
      if (shouldIgnore(fullPath)) continue;
      if (entry.isDirectory()) {
        const subCode = await collectCodeFiles(fullPath);
        results = [...results, ...subCode];
      } else if (entry.isFile()) {
        const ext = path.extname(entry.name).toLowerCase();
        if (config.codeExtensions.includes(ext)) {
          results.push(fullPath);
        }
      }
    }
  } catch (err) {
    console.error(`读取目录 ${dir} 失败:`, err.message);
  }
  return results;
}

/**
 * 搜索代码中是否引用图片
 */
async function findImageInCode(codeFiles, imageName) {
  const results = [];
  const imageNameWithoutExt = imageName.replace(path.extname(imageName), '');
  for (const codeFile of codeFiles) {
    try {
      const content = await fs.readFile(codeFile, 'utf8');
      if (content.includes(imageName) || content.includes(imageNameWithoutExt)) {
        results.push(codeFile);
      }
    } catch (err) {
      console.error(`读取 ${codeFile} 失败:`, err.message);
    }
  }
  return results;
}

/**
 * 按目录分组图片
 */
function groupImagesByDir(images) {
  const grouped = {};
  images.forEach(image => {
    if (!grouped[image.dir]) grouped[image.dir] = [];
    grouped[image.dir].push(image);
  });
  return grouped;
}

/**
 * 格式化相对路径
 */
function formatPath(fullPath) {
  return path.relative(config.projectRoot, fullPath);
}

/**
 * 主函数：扫描+统计体积
 */
async function main() {
  console.log('开始扫描图片使用情况（含体积统计）...');
  console.log(`项目根目录: ${config.projectRoot}\n`);

  // 并行收集图片和代码文件
  const [imageFiles, codeFiles] = await Promise.all([
    collectImageFiles(config.projectRoot),
    collectCodeFiles(config.projectRoot)
  ]);

  console.log(`发现 ${imageFiles.length} 个图片文件`);
  console.log(`发现 ${codeFiles.length} 个代码文件\n`);

  if (imageFiles.length === 0) {
    console.log('未发现图片文件，程序退出。');
    return;
  }

  // 新增：计算所有图片的加总体积（仅统计能正常获取体积的图片）
  const totalImageSize = imageFiles.reduce((sum, image) => {
    return sum + (image.size !== 0 ? image.size : 0);
  }, 0);
  const totalImageSizeKB = (totalImageSize / 1024).toFixed(2);

  // 按目录分组图片
  const imagesByDir = groupImagesByDir(imageFiles);
  const dirs = Object.keys(imagesByDir);

  // 结果存储：未使用目录、已使用目录（含体积）
  const unusedDirs = [];
  const usedDirs = {};

  // 遍历目录，分析图片使用情况 + 统计体积
  for (const dir of dirs) {
    usedDirs[dir] = {
      used: [],
      unused: [],
      totalSize: 0,     // 目录总体积（字节）
      totalSizeKB: '0.00' // 目录总体积（KB，保留两位小数）
    };

    const images = imagesByDir[dir];
    let hasUsedImages = false;
    let dirTotalSize = 0; // 临时累加目录体积

    for (const image of images) {
      dirTotalSize += image.size; // 累加字节数

      // 检查图片是否被代码引用
      const usage = await findImageInCode(codeFiles, image.name);
      if (usage.length > 0) {
        hasUsedImages = true;
        usedDirs[dir].used.push({ image, usedIn: usage });
      } else {
        usedDirs[dir].unused.push(image);
      }
    }

    // 计算目录总体积（KB 格式化）
    usedDirs[dir].totalSize = dirTotalSize;
    usedDirs[dir].totalSizeKB = (dirTotalSize / 1024).toFixed(2);

    // 标记“完全未使用的目录”
    if (!hasUsedImages) {
      unusedDirs.push({
        dir,
        totalSize: dirTotalSize,
        totalSizeKB: (dirTotalSize / 1024).toFixed(2)
      });
      delete usedDirs[dir]; // 从“已使用目录”中移除
    }
  }

  // 输出结果
  console.log('\n==================== 扫描结果 ====================');

  // 1. 输出“未使用的图片目录”（含总体积）
  if (unusedDirs.length > 0) {
    console.log('\n未被使用的图片目录（含总体积）:');
    unusedDirs.forEach(dirInfo => {
      console.log(`  - 目录: ${formatPath(dirInfo.dir)} | 总体积: ${dirInfo.totalSizeKB} KB (${dirInfo.totalSize} 字节)`);
    });
  }

  // 2. 输出“已使用的图片目录”（含单图体积 + 目录总体积）
  const usedDirsList = Object.keys(usedDirs);
  if (usedDirsList.length > 0) {
    console.log('\n部分/完全使用的图片目录（含体积统计）:');
    usedDirsList.forEach(dir => {
      const dirInfo = usedDirs[dir];
      console.log(`\n目录: ${formatPath(dir)} | 总体积: ${dirInfo.totalSizeKB} KB (${dirInfo.totalSize} 字节)`);

      // 已使用图片（含单图体积）
      if (dirInfo.used.length > 0) {
        console.log('  已使用的图片:');
        dirInfo.used.forEach(item => {
          console.log(`    - ${item.image.name} | 体积: ${item.image.sizeKB} KB (${item.image.size} 字节)`);
          item.usedIn.forEach(codeFile => {
            console.log(`      引用位置: ${formatPath(codeFile)}`);
          });
        });
      }

      // 未使用图片（含单图体积）
      if (dirInfo.unused.length > 0) {
        console.log('  未使用的图片:');
        dirInfo.unused.forEach(image => {
          console.log(`    - ${image.name} | 体积: ${image.sizeKB} KB (${image.size} 字节)`);
        });
      }
    });
  }

  console.log('\n==================== 扫描完成 ====================');
  
  // 新增：单独输出所有图片的加总体积
  console.log(`指定路径（${config.projectRoot}）下所有图片加总体积: ${totalImageSizeKB} KB (${totalImageSize} 字节)`);
}

// 执行主函数
main().catch(err => {
  console.error('程序执行出错:', err);
});